package com.ge.pp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

public class PPServerConnection {
	private PPViewer ppv;
    private static PPServerConnection ppserver = null;
	Socket sock;
	DataInputStream dis;
	DataOutputStream dos;
	Timer referralTimer;
	String userID;
	public static PPServerConnection getInstance(PPViewer ppViewer, String address, String docID) throws Exception
	{
		if(ppserver == null)
		{
			
			ppserver = new PPServerConnection(ppViewer, address, docID);
		}
		return(ppserver);
	}
	private PPServerConnection(PPViewer ppViewer, String address, String docID) throws Exception {
		try{ppv = ppViewer;
		userID = docID;
		System.out.println(address);
		System.out.println(docID);
		System.out.println();
		try {
			sock = new Socket(address, 42420);
			int error = 0;
			try 
			{
				dis = new DataInputStream(sock.getInputStream());
			} 
			catch (IOException e) 
			{				
				e.printStackTrace();
				error = 1;
				return;
			}
			try 
			{
				dos = new DataOutputStream(sock.getOutputStream());
			} 
			catch (IOException e) 
			{				
				e.printStackTrace();
				error = 2;
				return;
			}
			
			try 
			{						
				dos.writeInt(MessageTypes.HELLO);
				String hello_msg = "ClientID:"+docID;
				dos.writeInt(hello_msg.length());
				dos.writeBytes(hello_msg);				
			} 
			catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			// Set up the referral timeout loop	
			referralTimer = new Timer();
			
			referralTimer.schedule(new TimerTask() {
				@Override
				public void run() {					
					try {
						Vector<Case> cases = GetReferrals();
						for(Case c: cases) {
							c.referred = true;
							ppv.AddCase(c);
						}						
					} catch(Exception e) {
						e.printStackTrace();
					}
				}},0, 1000);				
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			System.out.print("socket failed 1");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.print("socket failed 1");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
		catch(Exception e)
		{
			throw e;
		}
	}
	
	protected Case GetCaseById(int id) throws Exception {
		Case c = null;
		
		try {
			dos.writeInt(MessageTypes.GET_CASE_INFO);
			dos.writeInt(id);
			int msgType = dis.readInt();
			if (msgType == MessageTypes.CASE_INFO) {			
				int caseID = dis.readInt(); 
				int patientID = dis.readInt();
				int caseNameLen = dis.readInt();
				byte [] b= new byte[caseNameLen];
				dis.readFully(b, 0, caseNameLen);
					
				c = new Case(caseID, patientID, new String(b));			
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw e;
		}
		return c;
	}
	
	protected Vector<Case> GetReferrals() throws Exception {
		try{Vector<Integer> caseIds = new Vector<Integer>();
		Vector<Case> cases = new Vector<Case>();
		try {			
			dos.writeInt(MessageTypes.GET_REFERRALS);
			dos.writeInt(this.userID.length());
			dos.writeBytes(userID);
			
			int msgType = dis.readInt();
			if (msgType == MessageTypes.REFERRAL_LIST) {
				int numCases = dis.readInt();
				for(int i=0; i<numCases; i++) {
					caseIds.add(dis.readInt());
				}
			}
			for(int caseid: caseIds) {
				Case c = GetCaseById(caseid);
				cases.add(c);
			}
		} catch(IOException ioe) {
			ioe.printStackTrace();
		}
		return cases;
		}
		catch(Exception e)
		{
			throw e;
		}
	}

	public Vector<Case> GetCases() throws Exception {
		try {
			Vector<Case> caseList = new Vector();
			dos.writeInt(MessageTypes.GET_CASES);
			
			int msgType = dis.readInt();
			if (msgType == MessageTypes.CASE_LIST) {
				int numCases = dis.readInt();
				for(int i=0; i<numCases; i++) {
					int caseID = dis.readInt();
					int patientID = dis.readInt();
					int caseNameLen = dis.readInt();
					byte [] b= new byte[caseNameLen];
					dis.readFully(b, 0, caseNameLen);
					
					Case c = new Case(caseID, patientID, new String(b));
					caseList.add(c);
				}
				return caseList;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw e;
		}
		return null;
	}
	
	public Patient GetPatient(int patientID) throws IOException {
		Patient p = null;
		try{
			dos.writeInt(MessageTypes.GET_PATIENT);
			dos.writeInt(patientID);
			int msgType = dis.readInt();
			if (msgType == MessageTypes.PATIENT_DATA) {
				int pid = dis.readInt();
				int len = dis.readInt();
				byte[] buf = new byte[len];
				dis.readFully(buf);
				String firstname = new String(buf);
				len = dis.readInt();
				buf = new byte[len];
				dis.readFully(buf);
				String lastname = new String(buf);
				p = new Patient(pid, firstname, lastname);	
			}
		} catch (IOException e) {
			throw e;
		}
		return p;
		
		
	}
	
	public void Disconnect() throws IOException {
		try {			
			dos.writeInt(MessageTypes.QUIT);
			
			dos.close();
			dis.close();
			sock.close();			
		} catch (IOException e) {
			throw e;
		}
	}

	public Vector<PPImage> GetImagesForCase(Case c) throws IOException {
		Vector<PPImage> imageList = new Vector<PPImage>();
		try {
			dos.writeInt(MessageTypes.GET_IMAGEINFO_FOR_CASE);		
			dos.writeInt(c.id);
			int msg = dis.readInt();
			if (msg == MessageTypes.IMAGE_LIST) {
				int count = dis.readInt();
				for(int i=0; i<count; i++) {
					int imageid = dis.readInt();
					int desc_len = dis.readInt();
					byte[] bdesc = new byte[desc_len];
					dis.readFully(bdesc,0, desc_len);
					String desc = new String(bdesc); 
					
					PPImage img = new PPImage(imageid, desc, "");
					imageList.add(img);
				}	
				return imageList;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw e;
		}
		return null;
	}
	
	public void GetImageData(PPImage img) throws IOException {
		try {
			dos.writeInt(MessageTypes.GET_IMAGE_DATA);
			dos.writeInt(img.id);
			int msg = dis.readInt();
			if (msg == MessageTypes.IMAGE_DATA) {
				int len = dis.readInt();
				img.data = new byte[len];
				dis.readFully(img.data);	
				img.createImageFromData();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw e;
		}
	}

	public void CheckoutCase(Case c) throws IOException {
		try {
			dos.writeInt(MessageTypes.CHECKOUT_CASE);
			dos.writeInt(c.id);
		} catch (IOException e) {			
			throw e;
		}
	}
	
	public void CheckinCase(Case c) throws IOException {
		try {
			dos.writeInt(MessageTypes.CHECKIN_CASE);
			dos.writeInt(c.id);
		} catch (IOException e) {			
			throw e;
		}		
	}

	public void ReferCase(Case c, String docID) throws IOException {
		// TODO Auto-generated method stub
		try {
			dos.writeInt(MessageTypes.REFER_CASE);
			dos.writeInt(c.id);
			dos.writeInt(docID.length());
			dos.writeChars(docID);
		}  catch (IOException e) {			
			throw e;
		}
	}

	public Vector<String> GetReferringDocs() throws IOException {
		Vector<String> docs = new Vector<String>();
		String s;
		try {
			dos.writeInt(MessageTypes.GET_OTHER_USERS);
			int msg = dis.readInt();
			if(msg == MessageTypes.OTHER_USERS){
				int count = dis.readInt();
				for(int i=0; i<count; i++) {
					int idlen = dis.readInt();
					byte[] id_s = new byte[idlen];
					dis.readFully(id_s);
					docs.add(new String(id_s));
				}
			}
		}  catch (IOException e) {			
			throw e;
		}
		return docs;
	}
}
